/**
XenSim simulates xenbal.
Copyright (C) 2006 Travis Vachon

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/
package xensim;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Hashtable;


public class Monitor {
	private FileWriter outfile;
	private SimGlobals globals;
	private Hashtable<Domain, WorkTimeLoad> domain_time_table;
	public Monitor(SimGlobals globals){
		domain_time_table = new Hashtable<Domain, WorkTimeLoad>();
		this.globals = globals; 
		
		for (Node node: globals.nodes){
			for (Domain domain: node.domains){
				domain_time_table.put(domain, new WorkTimeLoad(domain.timeOnCPU, globals.currentTime));
			}
		}
		
	}
	
	public Monitor(SimGlobals globals, String log_name){
		this(globals);
		try {
			outfile = new FileWriter(log_name);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			outfile = null;
			e.printStackTrace();
			System.exit(1);
		}
				
		globals.eventQueue.add(new MonitorEvent(globals.currentTime + SimGlobals.MONITOR_TIME, this, globals, outfile));
		
	}
	
	public double getDomainLoad(Domain domain){
		WorkTimeLoad domain_info = domain_time_table.get(domain);
		double load;
		if (domain_info != null){
			 if (globals.currentTime >= domain_info.time + globals.LOAD_UPDATE_TIME){
				 updateLoad(domain, domain_info);
			 }
			 return domain_info.getLoad(); 
		}else{
			domain_time_table.put(domain, new WorkTimeLoad(domain.timeOnCPU, globals.currentTime));
			return 0;
		}
		
	}
	
	private void updateLoad(Domain domain,WorkTimeLoad info){

		 info.setLoad((double)(domain.timeOnCPU - info.getWork())/(double)(globals.currentTime - info.getTime()));
		 info.setWork(domain.timeOnCPU);
		 info.setTime(globals.currentTime);
		 
	}
	
	public double getTotalLoad(Node node){
		double load = 0;
		for (Domain domain: node.domains){
			load += getDomainLoad(domain);
		}
		assert load < 1.0;
		return load;
	}
	
	public void stopMonitoring(){
		try {
			outfile.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	public class WorkTimeLoad{
		private double work;
		private double time;
		private double load;
		public WorkTimeLoad(double work, double time){
			this.work = work;
			this.time = time;
			this.load = 0;
			
		}
		public double getWork() {
			return work;
		}
		public void setWork(double work) {
			this.work = work;
		}
		public double getTime() {
			return time;
		}
		public void setTime(double time) {
			this.time = time;
		}
		public double getLoad() {
			return load;
		}
		public void setLoad(double load) {
			this.load = load;
		}
		
	}
}
